package com.vanke.devops.api.advice;

import com.vanke.core.bean.ApiBaseResponse;
import com.vanke.core.exception.VankeBusinessException;
import com.vanke.core.exception.VankeCommonExCodeEnum;
import com.vanke.core.util.JsonUtil;
import com.vanke.core.util.RequestIdUtils;
import com.vanke.core.util.StringUtil;
import org.apache.commons.lang3.builder.RecursiveToStringStyle;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 陈景阳
 * @since 16/10/8
 */
@Aspect
@Component
@Order
public class ApiMessageAdvice {


    private static final Log logger = LogFactory.getLog(ApiMessageAdvice.class);

    @Around("execution(public * com.vanke.devops..*..*Controller.*(..))")
    public Object invokeAPI(ProceedingJoinPoint pjp) {
        RequestIdUtils.generateRequestId();
        String apiName = pjp.getSignature().getName();
        Class<?> returnClazz = ((MethodSignature) pjp.getSignature()).getReturnType();

        Object returnValue = null;
        try {
            Object[] args = pjp.getArgs();
            if (logger.isInfoEnabled()) {
                if(args != null && args.length > 0){
                    for(Object o : args){
                        if(!(o instanceof HttpServletRequest) && !(o instanceof HttpServletResponse)) {
                            logger.info("@@" + apiName + " started,request:" + JsonUtil.toJson(o));
                        }
                    }

                }
            }
            returnValue = pjp.proceed();
            this.handleSuccess(returnValue);
        } catch (VankeBusinessException e) {
            returnValue = this.handleBusinessError(e, apiName, returnClazz);
        }
        catch (Throwable e) {
            returnValue = this.handleSystemError(e, apiName, returnClazz);
        }

        if (logger.isInfoEnabled()) {
            logger.info("@@" + apiName + " done,response:" + JsonUtil.toJson(returnValue));
        }

        return returnValue;
    }

    private Object handleBusinessError(VankeBusinessException e, String apiName, Class<?> returnClazz) {
        logger.error("@Meet error when bean " + apiName + "[" + e.getErrorCode() + "]:" + e.getErrorMessage(), e);
        Object returnValue = null;
        try {
            returnValue = returnClazz.newInstance();
            if (returnValue instanceof ApiBaseResponse) {
                ApiBaseResponse response = (ApiBaseResponse) returnValue;
                response.setRequestId(RequestIdUtils.getRequestId().toString());
                response.setResponseCode(e.getErrorCode());
                response.setResponseMessage(e.getErrorMessage());
            }
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }
        return returnValue;
    }

    private Object handleSystemError(Throwable e, String apiName, Class<?> returnClazz) {
        logger.error("@Meet unkonw error when bean " + apiName + ":" + e.getMessage(), e);
        Object returnValue = null;
        try {
            returnValue = returnClazz.newInstance();
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }
        if (returnValue instanceof ApiBaseResponse) {
            ApiBaseResponse response = (ApiBaseResponse) returnValue;
            response.setRequestId(RequestIdUtils.getRequestId().toString());
            response.setResponseCode(VankeCommonExCodeEnum.UNKNOW_ERROR.getCode());
            response.setResponseMessage(VankeCommonExCodeEnum.UNKNOW_ERROR.getMessage());
        }
        return returnValue;
    }

    private void handleSuccess(Object returnValue) {
        if (returnValue instanceof ApiBaseResponse) {
            // set request ID to response
            ApiBaseResponse response = (ApiBaseResponse) returnValue;
            if(StringUtil.isEmpty(response.getResponseCode())){
                response.setResponseCode(VankeCommonExCodeEnum.SUCCESS.getCode());
                response.setResponseMessage(VankeCommonExCodeEnum.SUCCESS.getMessage());
            }
            response.setRequestId(RequestIdUtils.getRequestId().toString());
        }
    }
}
